/**
 * \file Descriptor.h
 * \brief x86 descriptor tables
 * \author Corey Tabaka
 */

/*
   Copyright 2006 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#ifndef __KERNEL_DESCRIPTOR_H__
#define __KERNEL_DESCRIPTOR_H__

#include <ktypes.h>

/*
 * System Selectors
 */
#define CODE_SELECTOR	0x08
#define DATA_SELECTOR	0x10

#define USER_CODE_SELECTOR 0x23
#define USER_DATA_SELECTOR 0x2b

/*
 * Segment Selector Type
 */
typedef uint16 seg_sel_t;

/*
 * Segment Descriptor
 */

typedef struct {
	uint16 limit_15_0;
	uint16 base_15_0;
	uint8 base_23_16;
	union {
		uint8 priv;
		struct {
			uint8 type : 4;
			uint8 s : 1;
			uint8 dpl : 2;
			uint8 p : 1;
		};
	};
	struct {
		uint8 limit_19_16 : 4;
		uint8 avl : 1;
		uint8 reserved_0 : 1;
		uint8 d_b : 1;
		uint8 g : 1;
	};
	uint8 base_31_24;
} __attribute__ ((packed)) seg_desc_t;

/*
 * Gate Descriptors
 */

typedef struct {
	uint16 reserved_0;
	uint16 selector;
	uint8 reserved_1;
	union {
		uint8 priv;
		struct {
			uint8 type : 4;
			uint8 res_2 : 1; // always zero
			uint8 dpl : 2;
			uint8 p : 1;
		};
	};
	uint16 reserved_3;
} __attribute__ ((packed)) task_gate_t;

typedef struct {
	uint16 offset_15_0;
	seg_sel_t selector;
	uint8 reserved_0;
	union {
		uint8 priv;
		struct {
			uint8 type : 4;
			uint res_1 : 1;
			uint8 dpl : 2;
			uint8 p : 1;
		};
	};
	uint16 offset_31_16;
} __attribute__ ((packed)) int_gate_t;

typedef union {
	task_gate_t task;
	int_gate_t interrupt;
} int_desc_t;


/*
 * Descriptor Types
 */

#define SEG_TYPE_TSS		0x9
#define SEG_TYPE_TSS_BUSY	0xb
#define SEG_TYPE_TASK_GATE	0x5
#define SEG_TYPE_INT_GATE	0xe		// 32 bit
#define SEG_TYPE_DATA_RW	0x2
#define SEG_TYPE_CODE_RW	0xa

// The first 10 descriptors are for non-task operations
#define SEG_SYSTEM_RESERVED 10

class Descriptor {
	protected:
	
	Descriptor(void);
	~Descriptor(void);
	
	public:
	
	static void initialize(void);
	
	static seg_sel_t allocGlobalDescriptor(void);
	static void freeGlobalDescriptor(seg_sel_t sel);
	
	static seg_desc_t *getGlobalDescriptor(seg_sel_t sel);
	static void setGlobalDescriptor(seg_sel_t sel, void *base, uint32 size,
		uint8 present, uint8 ring, uint8 system, uint8 type, uint8 gran,
		uint8 bit);
		
	static void setTaskGate(uint8 interrupt, seg_sel_t sel, uint8 dpl,
		uint8 pres);
	static void setIntGate(uint8 interrupt, void *offset, uint8 dpl,
		uint8 pres);
};

#endif
